Introduction

In this workshop, we will explore how to create tables using the gt and gtExtras packages, utilizing the pizza place dataset. We will start with a basic table using base R to display pizza information, then enhance our visualization using the gt package to create a more polished and user-friendly table. Finally, we will upgrade our visualization further with the gtExtras package, adding even more features and styles to improve the overall presentation of our pizza menu.

The Data

Let’s look at our pizza sales dataset:

# Load and assign the pizza dataset to an object
data("pizzaplace")
pizza_data <- pizzaplace
head(pizza_data)
## # A tibble: 6 × 7
##   id          date       time     name        size  type    price
##   <chr>       <chr>      <chr>    <chr>       <chr> <chr>   <dbl>
## 1 2015-000001 2015-01-01 11:38:36 hawaiian    M     classic  13.2
## 2 2015-000002 2015-01-01 11:57:40 classic_dlx M     classic  16  
## 3 2015-000002 2015-01-01 11:57:40 mexicana    M     veggie   16  
## 4 2015-000002 2015-01-01 11:57:40 thai_ckn    L     chicken  20.8
## 5 2015-000002 2015-01-01 11:57:40 five_cheese L     veggie   18.5
## 6 2015-000002 2015-01-01 11:57:40 ital_supr   L     supreme  20.8

Basic Table (Before gt)

First, let’s create a summary table using basic R:

pizza_summary <- pizza_data %>%
  group_by(type, size) %>%
  summarize(
    total_sales = sum(price),
    num_orders = n(),
    avg_price = mean(price),
    .groups = 'drop'
  )

# Display as basic table
print(pizza_summary)
## # A tibble: 14 × 5
##    type    size  total_sales num_orders avg_price
##    <chr>   <chr>       <dbl>      <int>     <dbl>
##  1 chicken L         102339        4932      20.8
##  2 chicken M          65224.       3894      16.8
##  3 chicken S          28356        2224      12.8
##  4 classic L          74518.       4057      18.4
##  5 classic M          60582.       4112      14.7
##  6 classic S          69870.       6139      11.4
##  7 classic XL         14076         552      25.5
##  8 classic XXL         1007.         28      36.0
##  9 supreme L          94258.       4564      20.7
## 10 supreme M          66475        4046      16.4
## 11 supreme S          47464.       3377      14.1
## 12 veggie  L         104203.       5403      19.3
## 13 veggie  M          57101        3583      15.9
## 14 veggie  S          32387.       2663      12.2

Basic gt Features

Step 1: Basic gt Table

Let’s start with a simple gt table:

pizza_summary %>%
  gt(
    groupname_col = "type"
  )
size total_sales num_orders avg_price
chicken
L 102339.00 4932 20.75000
M 65224.50 3894 16.75000
S 28356.00 2224 12.75000
classic
L 74518.50 4057 18.36788
M 60581.75 4112 14.73292
S 69870.25 6139 11.38137
XL 14076.00 552 25.50000
XXL 1006.60 28 35.95000
supreme
L 94258.50 4564 20.65261
M 66475.00 4046 16.42981
S 47463.50 3377 14.05493
veggie
L 104202.70 5403 19.28608
M 57101.00 3583 15.93665
S 32386.75 2663 12.16175

Step 2: Adding Formatting

Now let’s add currency and number formatting:

pizza_summary %>%
  gt(
    groupname_col = "type"
  ) %>%
  fmt_currency(
    columns = c(total_sales, avg_price),
    currency = "USD"
  ) %>%
  fmt_number(
    columns = num_orders,
    decimals = 0
  )
size total_sales num_orders avg_price
chicken
L $102,339.00 4,932 $20.75
M $65,224.50 3,894 $16.75
S $28,356.00 2,224 $12.75
classic
L $74,518.50 4,057 $18.37
M $60,581.75 4,112 $14.73
S $69,870.25 6,139 $11.38
XL $14,076.00 552 $25.50
XXL $1,006.60 28 $35.95
supreme
L $94,258.50 4,564 $20.65
M $66,475.00 4,046 $16.43
S $47,463.50 3,377 $14.05
veggie
L $104,202.70 5,403 $19.29
M $57,101.00 3,583 $15.94
S $32,386.75 2,663 $12.16

Step 3: Adding Headers and Labels

Let’s improve the presentation with better headers:

pizza_summary %>%
  gt(
    groupname_col = "type"
  ) %>%
  fmt_currency(
    columns = c(total_sales, avg_price),
    currency = "USD"
  ) %>%
  fmt_number(
    columns = num_orders,
    decimals = 0
  ) %>%
  tab_header(
    title = "Pizza Sales Analysis",
    subtitle = "Sales breakdown by type and size"
  ) %>%
  cols_label(
    total_sales = "Total Sales",
    num_orders = "Number of Orders",
    avg_price = "Average Price",
    size = "Pizza Size"
  )
Pizza Sales Analysis
Sales breakdown by type and size
Pizza Size Total Sales Number of Orders Average Price
chicken
L $102,339.00 4,932 $20.75
M $65,224.50 3,894 $16.75
S $28,356.00 2,224 $12.75
classic
L $74,518.50 4,057 $18.37
M $60,581.75 4,112 $14.73
S $69,870.25 6,139 $11.38
XL $14,076.00 552 $25.50
XXL $1,006.60 28 $35.95
supreme
L $94,258.50 4,564 $20.65
M $66,475.00 4,046 $16.43
S $47,463.50 3,377 $14.05
veggie
L $104,202.70 5,403 $19.29
M $57,101.00 3,583 $15.94
S $32,386.75 2,663 $12.16

Step 4: Adding Visual Elements with gtExtras

Now let’s add some visual enhancements:

pizza_summary %>%
  gt(
    groupname_col = "type"
  ) %>%
  fmt_currency(
    columns = c(total_sales, avg_price),
    currency = "USD"
  ) %>%
  fmt_number(
    columns = num_orders,
    decimals = 0
  ) %>%
  tab_header(
    title = "Pizza Sales Analysis",
    subtitle = "Sales breakdown by type and size"
  ) %>%
  cols_label(
    total_sales = "Total Sales",
    num_orders = "Number of Orders",
    avg_price = "Average Price",
    size = "Pizza Size"
  ) %>%
  gt_theme_538() %>%
  data_color(
    columns = c(total_sales),
    colors = scales::col_numeric(
      palette = c("white", "#1F77B4"),
      domain = NULL
    )
  )
Pizza Sales Analysis
Sales breakdown by type and size
Pizza Size Total Sales Number of Orders Average Price
chicken
L $102,339.00 4,932 $20.75
M $65,224.50 3,894 $16.75
S $28,356.00 2,224 $12.75
classic
L $74,518.50 4,057 $18.37
M $60,581.75 4,112 $14.73
S $69,870.25 6,139 $11.38
XL $14,076.00 552 $25.50
XXL $1,006.60 28 $35.95
supreme
L $94,258.50 4,564 $20.65
M $66,475.00 4,046 $16.43
S $47,463.50 3,377 $14.05
veggie
L $104,202.70 5,403 $19.29
M $57,101.00 3,583 $15.94
S $32,386.75 2,663 $12.16

Advanced Features

Dark Theme Example

pizza_data %>%
  group_by(type) %>%
  summarize(
    total_sales = sum(price),
    num_orders = n(),
    avg_price = mean(price)
  ) %>%
  gt() %>%
  fmt_currency(
    columns = c(total_sales, avg_price),
    currency = "USD"
  ) %>%
  fmt_number(
    columns = num_orders,
    decimals = 0
  ) %>%
  gt_theme_dark() %>%
  tab_header(
    title = "Pizza Sales in Dark Theme",
    subtitle = "A different perspective on our data"
  )
Pizza Sales in Dark Theme
A different perspective on our data
type total_sales num_orders avg_price
chicken $195,919.50 11,050 $17.73
classic $220,053.10 14,888 $14.78
supreme $208,197.00 11,987 $17.37
veggie $193,690.45 11,649 $16.63

Summary Rows Feature

pizza_data %>%
  group_by(type) %>%
  summarize(
    total_sales = sum(price),
    num_orders = n(),
    avg_price = mean(price)
  ) %>%
  ungroup() %>%
  gt(
    groupname_col = "type"
  ) %>%
  fmt_currency(
    columns = c(total_sales, avg_price),
    currency = "USD"
  ) %>%
  fmt_number(
    columns = num_orders,
    decimals = 0
  ) %>%
  grand_summary_rows(
    columns = total_sales,
    fns = list(
      "Total" = ~sum(.)
    ),
    fmt = ~ fmt_currency(., currency = "USD")  
  ) %>%
  grand_summary_rows(
    columns = num_orders,
    fns = list(
      "Total" = ~sum(.)
    ),
    fmt = ~ fmt_number(., decimals = 0)  
  )
total_sales num_orders avg_price
chicken
$195,919.50 11,050 $17.73
classic
$220,053.10 14,888 $14.78
supreme
$208,197.00 11,987 $17.37
veggie
$193,690.45 11,649 $16.63
Total $817,860.05 49,574